package com.gaofans.nrpc.client.bootstrap;

import com.gaofans.nrpc.client.handler.ClientFilter;
import com.gaofans.nrpc.client.route.Router;
import com.gaofans.nrpc.common.compress.Codec;
import com.gaofans.nrpc.common.compress.CodecFactory;
import com.gaofans.nrpc.common.compress.Identity;
import com.gaofans.nrpc.common.id.IdGenerator;
import com.gaofans.nrpc.common.processor.Builder;
import com.gaofans.nrpc.common.serializer.SerializerFactory;
import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.SslContext;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * @author GaoFans
 */
public class ChannelManagerBuilder implements Builder<ChannelManager> {

    private final ChannelBootstrapConfig config;
    private final List<ClientFilter> filters;
    private final List<Router> routers;
    public ChannelManagerBuilder() {
        this.config = new ChannelBootstrapConfig();
        this.filters = new ArrayList<>();
        this.routers = new ArrayList<>();
    }

    public ChannelManagerBuilder codec(Codec codec){
        config.setCodec(codec);
        //注册codec
        if (CodecFactory.get(codec.getMessageEncoding()) == null){
            CodecFactory.register(codec.getMessageEncoding(),codec);
        }
        return this;
    }

    public ChannelManagerBuilder eventLoopThreadCount(int count){
        config.setEventLoopThreadCount(count);
        return this;
    }

    public ChannelManagerBuilder workerThreadCount(int count){
        config.setWorkerThreadCount(count);
        return this;
    }

    public ChannelManagerBuilder handlerThreadCount(int count){
        config.setHandlerThreadCount(count);
        return this;
    }

    @SuppressWarnings("rawtypes")
    public ChannelManagerBuilder setOption(ChannelOption key, Object value){
        config.setOptionMap(key,value);
        return this;
    }

    public ChannelManagerBuilder serializerFactory(SerializerFactory factory){
        config.setSerializerFactory(factory);
        return this;
    }

    public ChannelManagerBuilder serializerType(byte type){
        config.setSerializerType(type);
        return this;
    }

    public ChannelManagerBuilder version(short version){
        config.setVersion(version);
        return this;
    }

    public ChannelManagerBuilder idGenerator(IdGenerator idGenerator){
        config.setIdGenerator(idGenerator);
        return this;
    }

    public ChannelManagerBuilder processorExpireTime(Duration time){
        config.setProcessorExpireTime(time);
        return this;
    }

    public ChannelManagerBuilder processorMaximumSize(long size){
        config.setProcessorMaximumSize(size);
        return this;
    }

    public ChannelManagerBuilder readerIdleTimeSecond(int second){
        config.setReaderIdleTimeSecond(second);
        return this;
    }

    public ChannelManagerBuilder writerIdleTimeSecond(int second){
        config.setWriterIdleTimeSecond(second);
        return this;
    }

    public ChannelManagerBuilder sslContext(SslContext sslContext){
        config.setSslContext(sslContext);
        return this;
    }

    public ChannelManagerBuilder addFilter(ClientFilter filter){
        filters.add(filter);
        return this;
    }

    public ChannelManagerBuilder registerRouter(Router router){
        this.routers.add(router);
        return this;
    }

    @Override
    public ChannelManager build() {
        if (config.getCodec() == null){
            config.setCodec(new Identity());
        }
        if (config.getSerializerFactory() == null){
            config.setSerializerFactory(new SerializerFactory());
        }
        if (config.getSerializerFactory().getSerializer(config.getSerializerType()) == null){
            throw new IllegalStateException("找不到指定类型的序列化器");
        }
        if (config.getIdGenerator() == null){
            config.setIdGenerator(IdGenerator.getInstance());
        }
        if (config.getProcessorExpireTime() == null){
            config.setProcessorExpireTime(Duration.ofSeconds(30));
        }
        if (config.getProcessorMaximumSize() <= 0){
            config.setProcessorMaximumSize(1024);
        }
        ChannelBootstrap bootstrap = new ChannelBootstrap(config);
        for (ClientFilter filter : filters) {
            bootstrap.addFilter(filter);
        }
        SimpleChannelManager manager = new SimpleChannelManager(bootstrap);
        for (Router router : routers) {
            manager.register(router);
        }
        return manager;
    }
}
